package com.geor.gcv.ict.train;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.nutz.log.Loggers;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.slf4j.Logger;

/**
 * 训练数据抽象类
 * 
 * @author lusongnan
 *
 */
public abstract class TrainerAbstract implements MachineTrainer {

	public static int WIDTH;
	public static int HEIGHT;
	final static int TYPE;
	public static int TOTAL;

	protected Logger log = Loggers.get();
	protected boolean dealBool = false;

	static {
		HEIGHT = 30;
		WIDTH = 30;
		TOTAL = WIDTH * HEIGHT;
		TYPE = CvType.CV_32FC1;
	}

	protected int species = 0;
	
	@Override
	public void train(Map<String, List<Mat>> maps, String out) {
		
	}

	@Override
	public void train(String path, String out) throws Exception {
		// 获取训练数据 的文件路径集合
		List<File> paths = getFilePaths(path);
		Map<String, List<Mat>> mapMats = new HashMap<String, List<Mat>>();
		// 通过训练数据的文件 获取Mat map
		mapMats = getMatMap(paths);

		if (dealBool) {
			mapMats = deal(mapMats);
		}
		// 统计训练数据的数量 确paths定样本类型的数量
		species = getMatSize(mapMats);
		if (log.isDebugEnabled()) {
			log.debug("得到的文件大小为:" + paths.size());
			for (String str : mapMats.keySet()) {
				log.debug("文件夹" + str + "下有" + mapMats.get(str).size() + "个图像.");
			}
			log.debug("样本类型数量有" + species + "个");
		}
		// 创建需要训练的mat
		Mat[] mats = createTrainDataAndLabel(mapMats);
		// 开始训练
		train(mats[0], mats[1], out);
	}
	
	/**
	 * 训练
	 * 
	 * @param trainData
	 *            训练mat
	 * @param label
	 *            样本类型
	 * @param out
	 *            输出路径
	 * @return
	 */
	public abstract void train(Mat trainData, Mat label, String out);

	public int getMatSize(Map<String, List<Mat>> mapMats) {
		int count = 0;
		for (String key : mapMats.keySet()) {
			count += mapMats.get(key).size();
		}
		return count;
	}

	/**
	 * 获取训练数据文件目录集合
	 * 
	 * @return
	 */
	public List<File> getFilePaths(String string) {
		List<File> paths = new ArrayList<File>();

		File file = new File(string);
		String[] fs = file.list();
		for (String path : fs) {
			paths.add(new File(string + "\\" + path));
			if (log.isDebugEnabled()) {
				log.debug(string + "\\" + path);
			}
		}

		return paths;
	}

	/**
	 * 得到Mat map
	 * 
	 * @param paths
	 * @return
	 */
	public Map<String, List<Mat>> getMatMap(List<File> paths) {
		Map<String, List<Mat>> maps = new HashMap<String, List<Mat>>();
		for (int i = 0; i < paths.size(); i++) {
			File files[] = paths.get(i).listFiles();
			List<Mat> mats = new ArrayList<Mat>();
			for (File file : files) {
				mats.add(Imgcodecs.imread(file.getAbsolutePath()));
			}
			maps.put(paths.get(i).getName(), mats);
		}

		return maps;
	}

	/**
	 * 初始化训练Mat和样本类型Mat
	 * 
	 * @param mapMats
	 * @return
	 */
	public Mat[] createTrainDataAndLabel(Map<String, List<Mat>> mapMats) {
		// 需要训练的样本数据
		Mat trainData = new Mat(species, TOTAL, TYPE);
		// 标记样本数据的类型
		Mat labels = new Mat(species, 1, TYPE);
		int labels_row = 0;
		for (String i : mapMats.keySet()) {
			List<Mat> mats = mapMats.get(i);
			for (int n = 0; n < mats.size(); n++, labels_row++) {
				labels.put(labels_row, 0, Integer.parseInt(i));
				int count = 0;
				for (int i1 = 0; i1 < HEIGHT; i1++) {
					for (int j1 = 0; j1 < WIDTH; j1++) {
						trainData.put(labels_row, count++, mats.get(n).get(i1, j1)[0]);
					}
				}
			}
		}

		Mat mats[] = { trainData, labels };
		return mats;
	}

	public Map<String, List<Mat>> deal(Map<String, List<Mat>> maps) {
		return maps;
	}
}
